package any.xpath;

import java.util.Iterator;

import org.jaxen.DefaultNavigator;
import org.jaxen.FunctionCallException;
import org.jaxen.JaxenConstants;
import org.jaxen.NamedAccessNavigator;
import org.jaxen.Navigator;
import org.jaxen.XPath;
import org.jaxen.javabean.JavaBeanXPath;
import org.jaxen.util.SingleObjectIterator;

import any.ImmutableAny;

/**
 * Interface for navigating around a JavaBean object model.
 * 
 * <p>
 * This class is not intended for direct usage, but is used by the Jaxen engine
 * during evaluation.
 * </p>
 * 
 * @see XPath
 */
public class AnythingDocumentNavigator extends DefaultNavigator implements NamedAccessNavigator {

	private static final long serialVersionUID = -1768605107626726499L;

	/**
	 * Singleton implementation.
	 */
	private static final AnythingDocumentNavigator instance = new AnythingDocumentNavigator();

	/**
	 * Retrieve the singleton instance of this <code>AnythingDocumentNavigator</code>.
	 */
	public static Navigator getInstance() {
		return instance;
	}
	

	public boolean isElement(Object obj) {
		return (obj instanceof AnythingElement);
	}

	public boolean isComment(Object obj) {
		return false;
	}

	public boolean isText(Object obj) {
		return (obj instanceof String);
	}

	public boolean isAttribute(Object obj) {
		return false;
	}

	public boolean isProcessingInstruction(Object obj) {
		return false;
	}

	public boolean isDocument(Object obj) {
		return false;
	}

	public boolean isNamespace(Object obj) {
		return false;
	}

	public String getElementName(Object obj) {
		return ((AnythingElement) obj).getName();
	}

	public String getElementNamespaceUri(Object obj) {
		return "";
	}

	public String getElementQName(Object obj) {
		return "";
	}

	public String getAttributeName(Object obj) {
		return "";
	}

	public String getAttributeNamespaceUri(Object obj) {
		return "";
	}

	public String getAttributeQName(Object obj) {
		return "";
	}

	@Override
	public Iterator<?> getChildAxisIterator(Object contextNode) {
		AnythingElement anyElement = (AnythingElement)contextNode;
		return new AnythingElement.Itr(anyElement, anyElement.getAny().iterator());
	}

	/**
	 * Retrieves an <code>Iterator</code> over the child elements that match the
	 * supplied name.
	 * 
	 * @param contextNode
	 *            the origin context node
	 * @param localName
	 *            the local name of the children to return, always present
	 * @param namespacePrefix
	 *            the prefix of the namespace of the children to return
	 * @param namespaceURI
	 *            the namespace URI of the children to return
	 * @return an Iterator that traverses the named children, or null if none
	 */
	public Iterator<?> getChildAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
		AnythingElement anyElement = (AnythingElement)contextNode;
		ImmutableAny any = anyElement.getAny();
		if (any.containsKey(localName)) {
			return new SingleObjectIterator(new AnythingElement(anyElement, localName, any.get(localName)));
		} else {
			return JaxenConstants.EMPTY_ITERATOR;
		}
	}

	@Override
	public Iterator<?> getParentAxisIterator(Object contextNode) {
		if (contextNode instanceof AnythingElement) {
			return new SingleObjectIterator(((AnythingElement)contextNode).getParent());
		} else {
			return JaxenConstants.EMPTY_ITERATOR;
		}
	}

	@Override
	public Iterator<?> getAttributeAxisIterator(Object contextNode) {
		return JaxenConstants.EMPTY_ITERATOR;
	}

	/**
	 * Retrieves an <code>Iterator</code> over the attribute elements that match
	 * the supplied name.
	 * 
	 * @param contextNode
	 *            the origin context node
	 * @param localName
	 *            the local name of the attributes to return, always present
	 * @param namespacePrefix
	 *            the prefix of the namespace of the attributes to return
	 * @param namespaceURI
	 *            the namespace URI of the attributes to return
	 * @return an Iterator that traverses the named attributes, not null
	 */
	public Iterator<?> getAttributeAxisIterator(Object contextNode, String localName, String namespacePrefix, String namespaceURI) {
		return JaxenConstants.EMPTY_ITERATOR;
	}

	@Override
	public Iterator<?> getNamespaceAxisIterator(Object contextNode) {
		return JaxenConstants.EMPTY_ITERATOR;
	}

	@Override
	public Object getDocumentNode(Object contextNode) {
		return null;
	}

	@Override
	public Object getParentNode(Object contextNode) {
		if (contextNode instanceof AnythingElement) {
			return ((AnythingElement)contextNode).getParent();
		} else {
			return JaxenConstants.EMPTY_ITERATOR;			
		}

	}

	public String getTextStringValue(Object obj) {
		if (obj instanceof AnythingElement) {
			return ((AnythingElement)obj).getAny().asString("");
		}
		return obj.toString();
	}

	public String getElementStringValue(Object obj) {
		if (obj instanceof AnythingElement) {
			return ((AnythingElement)obj).getAny().asString("");
		}
		return obj.toString();
	}

	public String getAttributeStringValue(Object obj) {
		return obj.toString();
	}

	public String getNamespaceStringValue(Object obj) {
		return obj.toString();
	}

	public String getNamespacePrefix(Object obj) {
		return null;
	}

	public String getCommentStringValue(Object obj) {
		return null;
	}

	@Override
	public String translateNamespacePrefixToUri(String prefix, Object context) {
		return null;
	}

	@Override
	public short getNodeType(Object node) {
		return 0;
	}

	@Override
	public Object getDocument(String uri) throws FunctionCallException {
		return null;
	}

	@Override
	public String getProcessingInstructionTarget(Object obj) {
		return null;
	}

	@Override
	public String getProcessingInstructionData(Object obj) {
		return null;
	}

	public XPath parseXPath(String xpath) throws org.jaxen.saxpath.SAXPathException {
		return new JavaBeanXPath(xpath);
	}

}
